const userModel = require("../model/user");
const roleModel = require("../model/role");
const departmentModel = require("../model/department");
const jwt = require("jsonwebtoken");

// 接口白名单
const whiteList = [
	"/api/user/login", // 登录接口
];

// 权限中间件
module.exports = async (req, res, next) => {
	const token = req.headers.token;

	// 如果是登录接口, 则直接放行.
	if (whiteList.includes(req.path)) return next();
	// 判断是否有Token, 如果没Token则返回401.
	if (!token) return res.json({ code: 401, msg: "请先登录!" });

	// 验证Token
	let userId = undefined;
	try {
		const userInfo = jwt.verify(token, process.env.JWT_SECRET);
		userId = userInfo.id;
	} catch (err) {
		return res.json({ code: 401, msg: "登录已过期, 请重新登录!" });
	}

	// 查询用户信息
	let userInfo = {};
	try {
		userInfo = await userModel.findById(userId).lean();
		// 如果账号状态异常, 则返回错误信息
		if (userInfo.status !== "enable") return res.json({ code: 401, msg: "账号状态异常, 请联系管理员!" });

		req.userInfo = userInfo;
	} catch (err) {
		return res.json({ code: 401, msg: "鉴权失败, 服务器错误!" });
	}

	// 如果是管理员, 则直接放行
	if (userInfo.isSuper) return next();

	// 查询用户部门表, 判断部门状态是否正常
	try {
		const departmentInfo = await departmentModel.findById(userInfo.department).lean();
		if (departmentInfo.status === "disable") return res.json({ code: 401, msg: "部门状态异常, 请联系管理员!" });
		userInfo.department = departmentInfo;
	} catch (e) {
		return res.json({ code: 401, msg: "部门状态异常, 请联系管理员!" });
	}

	// 查询用户的身份_联表查询了权限表
	try {
		const roleInfoRes = await roleModel.aggregate([
			// 通过角色id数组, 查询所有的权限
			{ $match: { _id: { $in: userInfo.role } } },
			{
				$lookup: {
					from: "permissions",
					localField: "permissions",
					foreignField: "_id",
					as: "permissions",
				},
			},
		]);
		// 提取权限和角色
		const roleAndPermissionsInfo = roleInfoRes.reduce(
			(pre, cur) => {
				pre.roleArr.push(cur.key);
				pre.permissionsArr = new Set([...pre.permissionsArr, ...cur.permissions.map((item) => item.key)]);

				return pre;
			},
			{ permissionsArr: new Set(), roleArr: [] }
		);
		// 为用户覆盖原有的权限和角色属性值
		userInfo.role = roleAndPermissionsInfo.roleArr;
		userInfo.permissions = Array.from(roleAndPermissionsInfo.permissionsArr);
	} catch (e) {
		return res.json({ code: 401, msg: "权限状态异常, 请联系管理员!" });
	}

	// 将信息传递给后续流程
	req.userInfo = userInfo;
	next();
};
